let cache = {};
async function fetchFrom(link, options) {
	let tab = cache.link == link ? await chrome.tabs.get(cache.tab.id) : null;
	if (!tab) {
		await chrome.declarativeNetRequest.updateDynamicRules({
			removeRuleIds: [1],
			addRules: [
				{
					id: 1,
					priority: 1,
					action: {
						type: "modifyHeaders",
						responseHeaders: [{header: "Content-Security-Policy", operation: "remove"}],
					},
					condition: {
						resourceTypes: ["main_frame"],
					},
				},
			],
		});
		tab = await chrome.tabs.create({url: link, index: 0, active: false});
		await new Promise((resolve) =>
			chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo) {
				if (tabId == tab.id && changeInfo.status == "complete") {
					chrome.tabs.onUpdated.removeListener(listener);
					resolve();
				}
			})
		);
		await chrome.declarativeNetRequest.updateDynamicRules({
			removeRuleIds: [1],
		});
	}
	cache = {link, tab};
	if (options.body) {
		if (!options.method) options.method = "POST";
		if (typeof options.body == "object") {
			options.headers = Object.assign({"Content-Type": "application/json"}, options.headers);
			options.body = JSON.stringify(options.body);
		}
	}
	return await chrome.scripting
		.executeScript({
			target: {tabId: tab.id},
			func: function (options) {
				return fetch(options.url, {
					method: options.method,
					body: options.body,
					headers: options.headers,
				}).then((x) => x.json());
			},
			args: [options],
		})
		.then((x) => x[0].result);
}
